package com.jinpin.gateway.authorization;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.common.utils.HttpMethod;
import com.jinpin.core.constant.RedisConstant;
import com.jinpin.core.dto.JwtDto;
import com.jinpin.redis.tran.RedisFile;
import com.jinpin.redis.utils.RedisUtil;
import com.nimbusds.jose.JWSObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.text.ParseException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 鉴权管理器，用于判断是否有资源的访问权限
 */
@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        ServerWebExchange exchange = authorizationContext.getExchange();
        ServerHttpRequest request = exchange.getRequest();
        //从Redis中获取当前路径需要的角色和权限
        String uri = request.getURI().getPath();
        Object obj = redisTemplate.opsForHash().get(RedisConstant.RESOURCE_ROLES_MAP, uri);
        List<String> authorities = Convert.toList(String.class, obj);
        // option 请求，全部放行
        if (Objects.requireNonNull(request.getMethod()).toString().equals(HttpMethod.OPTIONS)) {
            return Mono.just(new AuthorizationDecision(true));
        }
        // todo 没有设置权限的url全部拦截
        if (authorities.size() == 0) {
            return Mono.just(new AuthorizationDecision(false));
        }
        //  从redis中取出角色 是能访问的角色放行
        List<String> roles = redisUtil.getCacheObject(RedisFile.USER + jwtDto(request).getSub());
        for (String r : roles) {
            if (authorities.contains(r))
                return Mono.just(new AuthorizationDecision(true));
        }
        return Mono.just(new AuthorizationDecision(false));
    }

    // 解析token
    public JwtDto jwtDto(ServerHttpRequest request) {
        String token = Objects.requireNonNull(request.getHeaders().getFirst("Authorization")).replace("Bearer ", "");
        String json = null;
        try {
            json = JWSObject.parse(token).getPayload().toString();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return JSONUtil.toBean(json, JwtDto.class);
    }

}
